/*
* Copyright (c) Joan-Manuel Marques 2013. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This file is part of the practical assignment of Distributed Systems course.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this code.  If not, see <http://www.gnu.org/licenses/>.
*/

package lsimElement.recipesService;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Properties;
import java.util.Random;
import edu.uoc.dpcs.lsim.LSimFactory;
import edu.uoc.dpcs.lsim.utils.LSimParameters;
import util.Serializer;
import lsim.application.handler.Handler;
import lsim.communication.Host;

/**
 * @author Joan-Manuel Marques
 * July 2013
 *
 */
public class WorkerInitHandler implements Handler {
	
	private Properties properties;
	private Host localHost;
	
	@Override
	public Object execute(Object obj) {
		LSimParameters params = (LSimParameters) obj;
		
		// TODO: omplir la variable properties amb els paràmetres rebuts
		
		
		// obtain local host address
		String hostAddress =  getHostAddress();
		
		// TODO: Parametritzar el port base
		int hostPort = 29010;
		// assign service to port
		while (!servicePublished(hostPort)){
			hostPort++;
		}	
		
		
		String id = null;
		Random rnd = new Random();
		// create id
		id = /*groupId+"@"+*/hostAddress+":"+(System.currentTimeMillis()%100000)+":"+(rnd.nextLong()%100000);
		System.out.println("WorkerInitHandler --> id: "+id);

		// create local node information to send to coordinator node
		localHost = new Host(hostAddress, hostPort, id);
		
        // init return value
		Object returnObj = null;
		try {
			returnObj = Serializer.serialize(localHost);
		} catch (IOException e) {
			// TODO Auto-generated catch block		List<Object> params = (List<Object>) obj;

			e.printStackTrace();
		}

		return returnObj;
	}

	public Host getLocalHost(){
		return localHost;
	}
	
	public Properties getParams(){
		return properties; 
	}
	
	/**
	 * Auxiliary methods
	 */
	
	private String getHostAddress(){
		Socket socket = null;
        ObjectInputStream in = null;
        String testServerAddress = "sd.uoc.edu";
        int port = 54324;
        String hostAddress = null;
        try {
        	socket = new Socket(testServerAddress, port);
        	in = new ObjectInputStream(socket.getInputStream());
        	hostAddress = (String) in.readObject();
        	in.close();
        	socket.close();
        } catch (IOException e) {
        	// System.err.println("WorkerInitiHandler -- getHostAddress -- Couldn't get I/O for "
        	// + "the connection to: " + testServerAddress);
        	LSimFactory.getWorkerInstance().log(
    				"",
    				"WorkerInitiHandler -- getHostAddress -- Couldn't get I/O for "
    	        			+ "the connection to: " + testServerAddress
        			);
        	System.exit(1);
        } catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        return hostAddress;
	}
	
	public boolean servicePublished(int port) {
		// check if port is used by a UDP service
		DatagramSocket ds = null;
		try {
			ds = new DatagramSocket(null);
			ds.setReuseAddress(true);
			ds.bind(new InetSocketAddress(port));
			// ds = new DatagramSocket(port);
			// ds.setReuseAddress(true);
		} catch (IOException e) {
			return false;
		} finally {
			if (ds != null) {
				ds.close();
			}
		}
		// assign service to port
		// starts a thread to deal with TSAE sessions from partner servers
		ServerSocket serverSocket = null;
		try {
			serverSocket = new ServerSocket();
			serverSocket.setReuseAddress(true);
			serverSocket.bind(new InetSocketAddress(port));
			// serverSocket = new ServerSocket(port);
			// serverSocket.setReuseAddress(true);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			// e.printStackTrace();
			return false;
		} finally{
			if (serverSocket != null) {
				try {
					serverSocket.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					// e.printStackTrace();
				}
			}
		}
		return true;
	}
}